package tcpClient;


import java.util.ArrayList;

import javax.crypto.BadPaddingException;
import javax.crypto.spec.SecretKeySpec;

import org.apache.log4j.Logger;

import service.SecurityService;

import channels.AESChannel;
import channels.Channel;
import channels.SecureChannel;
import channels.TCPChannel;
import domain.User;



public class AuctionClientThread extends Thread {

	private Channel myChannel;
	private boolean isActive = true;
	private AuctionClient auctionClient = null;
	private SecurityService securityService;
	private boolean decryptMePlease = false;
	private byte[] clientChallenge;
	private static final Logger log = Logger.getLogger(AuctionClientThread.class);
	private boolean aesEncryptionActive = false;
	private boolean sendMessage = true;

	private boolean isConfirm = false;
	private String username = null;
	private ConfirmationHolder confirmationHolder;
	private ArrayList<User> loggedInUsers = new ArrayList<User>();

	public AuctionClientThread(Channel myChannel, AuctionClient auctionClient) {
		this.myChannel = myChannel;
		this.auctionClient = auctionClient;
		this.securityService = SecurityService.getInstance();
	}

	public void run() {
		String response;

		while(isActive) {

			response = myChannel.read();
			if(response == null) {
				serverClosed();
				break;
			}
			if(decryptMePlease == true) {
				byte[] code = securityService.decodeBase64(response.getBytes());
				try {
					code = securityService.decryptMessage(code);
					response = new String(code);
				} catch (BadPaddingException e) {

				}
				decryptMePlease = false;
			}
			if(aesEncryptionActive == true && !response.startsWith("Successfully logged out")) {

				String[] substrings = response.split(" ");

				String hash = new String(securityService.decodeBase64(substrings[substrings.length - 1].getBytes()));
				String message = "";
				for(int i = 0; i<substrings.length-1; i++) {
					message += substrings[i];
					if(i<substrings.length-2) message += " ";
				}
				if(!hash.equals(new String(securityService.generateHMac(message)))) {

					if(sendMessage) {
						auctionClient.resendLastMessage();
						sendMessage = false;
					} else {
						sendMessage = true;
					}

					System.out.println("Wrong HMAC, message could be forged:");
				} else {
					sendMessage = true;
				}

				response = message;

			}
			if(response.startsWith("!confirmed ")){
				String[] string2 = response.split(" ");
				auctionClient.stopSleep();
				//send bid-command
				if(username.equals(string2[2])){
					auctionClient.groupBid(string2[3] + " " + string2[4] + " " + string2[2]);							
				}						
			}
			if(response.startsWith("!rejected ")){
				auctionClient.stopSleep();
			}
			log.info("reading: "+response);

			if(response.startsWith("!ok ")) {
				String[] substrings = response.split(" ");
				if(substrings.length == 5 && new String(clientChallenge).equals(substrings[1])) {
					byte[] serverChallenge = substrings[2].getBytes();
					auctionClient.setServerChallenge(serverChallenge);
					byte[] iv = securityService.decodeBase64(substrings[4].getBytes());
					byte[] sKey = securityService.decodeBase64(substrings[3].getBytes());
					securityService.setIV(iv);
					securityService.setSecretKey(new SecretKeySpec(sKey,"AES"));
					myChannel = AESChannel.getInstance();
					aesEncryptionActive = true;
					AESChannel.getInstance().setSecurityService(securityService);
					log.info("using aes channel now. sending server challenge.");
					myChannel.send(new String(serverChallenge));
				} else {
					log.error("substrings.length = "+substrings.length+"\n"+new String(clientChallenge)+"\n"+substrings[1]);
				}
			}
			if(response.startsWith("Successfully logged in")) {
				myChannel.send("!getClientList");
				String[] substrings = response.split(" ");
				this.username =substrings[4].substring(0,substrings[4].length()-1); 
				//auctionClient.setUsername(substrings[4].substring(0,substrings[4].length()-1));
				auctionClient.loggedIn(true);
			}
			if(response.startsWith("Successfully logged out")) {
				/*String[] substrings = response.split(" ");
						auctionClient.setUsername(substrings[4].substring(0,substrings[4].length()-1));*/
				auctionClient.loggedIn(false);
				aesEncryptionActive = false;
				myChannel = TCPChannel.getInstance();
				username = null;
				log.info("using tcp channel now.");
			}

			if(response.startsWith("Active Clients:")) {
				String[] parts = response.split("\n");
				for(int i=1;i<parts.length;i++) {
					String[] subparts = parts[i].split(":");
					//log.info("parts.length = "+parts.length);
					String address = subparts[0];
					subparts = subparts[1].split(" - ");
					//log.info("address = "+address+", parts.length = "+subparts.length);
					int prt = Integer.parseInt(subparts[0]);
					String usrnm = subparts[1];
					//log.info("address: "+address+", port: "+prt+", name: "+usrnm);
					loggedInUsers.add(new User(usrnm,prt,address));
				}
			} 
			if(!response.startsWith("!ok ")&&!response.startsWith("Active Clients:")) System.out.println(response);


		}

		return;
	}

	private void serverClosed() {
		auctionClient.serverClosed();

	}

	public void closeThread() {
		this.isActive=false;
	}

	public void setChallenge(byte[] clientChallenge) {
		this.clientChallenge = clientChallenge;
		myChannel = SecureChannel.getInstance();
		this.decryptMePlease = true;
		SecureChannel.getInstance().setSecurityService(securityService);
		log.info("using secure channel now.");

	}
}
